﻿/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is tyzoh.jp code.
 *
 * The Initial Developer of the Original Code is Kazutaka Kurihara.
 * Portions created by the Initial Developer are Copyright (C) 2007
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * ***** END LICENSE BLOCK ***** */
using System;
using System.Drawing;
using System.Collections;
using Microsoft.Ink;
using System.Windows.Forms;
//using NUnit.Framework;
using Qurihara.QBasic;
using Qurihara.Anm;

namespace Qurihara
{
	public class StrokeElement : WakuElement , IPlayBackAnmElement
	{
		public static Control parent = null;
		// Set static variables before use
		public static InkCollector inkCollector = null;
		// すべてのStrokeElementを保持するリスト。ページを変えるときにクリアすること。
		//public static QBasic.QArrayList allStrokeElementList = new QBasic.QArrayList(); 
		public static FigureElementList allStrokeElementList = new FigureElementList();
		protected static Strokes strokes;
		public static void Init(InkCollector ic,Control _parent)
		{
			StrokeElement.inkCollector = ic;
			parent = _parent;
			ic.AutoRedraw = false;
			allStrokeElementList.Clear();
		}
		public static void ResetInk(Ink ink)
		{
			StrokeElement.allStrokeElementList.Clear();
			if (StrokeElement.inkCollector.Ink != null) 
			{
				while(StrokeElement.inkCollector.CollectingInk)
				{
					System.Diagnostics.Debug.WriteLine("now collecting ink. please wait!");
				}
				if (StrokeElement.inkCollector.Ink.Strokes.Count > 0)
					StrokeElement.inkCollector.Ink.DeleteStrokes();
			}
			bool initiallyEnabled = false;
			if (StrokeElement.inkCollector.Enabled)
			{
				StrokeElement.inkCollector.Enabled = false;
				initiallyEnabled =true;
			}
			//Ink oldInk = StrokeElement.inkCollector.Ink = ink;
			StrokeElement.inkCollector.Ink = ink;
			if (initiallyEnabled)
			{
				StrokeElement.inkCollector.Enabled = true;
			}
		}
		~StrokeElement()
		{
			StrokeElement.allStrokeElementList.Remove(this);
		}
/*		public static StrokeElement GetStrokeElementFromStroke(Stroke s)
		{
			StrokeElement se;
			IEnumerator enume = StrokeElement.allStrokeElementList.GetEnumerator();
			while(enume.MoveNext())
			{
				se = (StrokeElement)enume.Current;
				if (se.stroke.Id.Equals(s.Id))
				{
					return se;
				}
			}
			return null;
		}
*/
		public static void Load(byte[] b)
		{
			StrokeElement.inkCollector.Ink.Load(b);
			CreateIDTable();
		}
		protected static Hashtable idTable= new Hashtable(1000);
		protected static void CreateIDTable()
		{
			idTable.Clear();
			Strokes ss = inkCollector.Ink.Strokes;
			for(int i=0;i<ss.Count;i++)
			{
				idTable.Add(ss[i].Id,i);
				//if(ss[i].Deleted) System.Diagnostics.Debug.Fail("deleted!");
			}

			strokes = ss;
		}
		protected Stroke stroke;
		// added 050809
		public Stroke Stroke
		{
			get{return stroke;}
		}
		//protected Point[] pt;
		protected int Id;

		public int ID
		{
			set{Id = value;}
			get{return Id;}
		}

		public StrokeElement(Control parentCont,int prio,Rectangle r,Stroke s) : base(parentCont,prio,r)
		{
			stroke = s;
			Id = s.Id;
			//pt = s.GetPoints();
			StrokeElement.allStrokeElementList.Add(this);
		}
		
		public StrokeElement(Control parentCont,int prio,Rectangle r,int id) : base(parentCont,prio,r)
		{
			Id = id;
			//stroke = QBasic.InkUtil.GetStrokeFromID(inkCollector.Ink,id);// costly
			int sId = (int)idTable[id];
			// ↓これが１回４０ｋｂくらいメモリを食っている！ HashTableづくりのときに一度だけ取得する．
			//Strokes ss = inkCollector.Ink.Strokes;
			//stroke = ss[sId];
			//ss = null;
			stroke = strokes[sId];

			//pt = stroke.GetPoints();
			StrokeElement.allStrokeElementList.Add(this);
		}

		public override void moveRerative(int addx,int addy)
		{
			base.moveRerative(addx,addy);
			Point p = new Point(addx,addy);
			//inkCollector.Renderer.PixelToInkSpace(inkCollector.Handle,ref p);
			Graphics g = parentControl.CreateGraphics();
			inkCollector.Renderer.PixelToInkSpace(g,ref p);
			g.Dispose();
			stroke.Move((float)p.X,(float)p.Y);
			//pt = stroke.GetPoints();
		}
		public override void Resize(int x,int y,int w,int h)
		{
			base.Resize(x,y,w,h);
			Point p1 = new Point(x,y);
			Point p2 = new Point(w,h);
			Point [] p = {p1,p2};
			//inkCollector.Renderer.PixelToInkSpace(inkCollector.Handle,ref p);
			Graphics g = parentControl.CreateGraphics();
			inkCollector.Renderer.PixelToInkSpace(g,ref p);
			g.Dispose();
			//Rectangle r = new Rectangle(p1.X,p1.Y,p2.X,p2.Y);
			Rectangle r = stroke.GetBoundingBox();
			r.X += p[0].X;
			r.Y += p[0].Y;
			r.Width += p[1].X;
			r.Height += p[1].Y;
			stroke.ScaleToRectangle(r);
			//pt = stroke.GetPoints();
		}

		// なんらかの原因（主に不手際）でインクとオブジェクトのBoundingBoxがずれたときにこれらを同期させる。
		public void SynchronizeBoundingBox()
		{
			Rectangle r = boundingBox;
			Point p1 = new Point(r.X,r.Y);
			Point p2 = new Point(r.Width,r.Height);
			Point [] p = {p1,p2};
			//inkCollector.Renderer.PixelToInkSpace(inkCollector.Handle,ref p);
			Graphics g = parentControl.CreateGraphics();
			inkCollector.Renderer.PixelToInkSpace(g,ref p);
			g.Dispose();
			r.X = p[0].X;
			r.Y = p[0].Y;
			r.Width = p[1].X;
			r.Height = p[1].Y;
			stroke.ScaleToRectangle(r);
		}

		protected float prevPlayPosition=0f;
		protected Stroke drawStroke=null;
		public override void draw(Graphics g)
		{
			if (visible)
			{
				if (drawStroke == null || prevPlayPosition != playPosition)
				{
					if (drawStroke != null && !drawStroke.Equals(stroke)) inkCollector.Ink.DeleteStroke(drawStroke);
					if(playPosition == 1.0f)
					{
						drawStroke = stroke;
					}
					else
					{
						Point [] ps = stroke.GetPoints(0,(int)((stroke.PacketCount-1)*playPosition)+1);
						drawStroke = inkCollector.Ink.CreateStroke(ps);
						drawStroke.DrawingAttributes = stroke.DrawingAttributes;
					}
					prevPlayPosition = playPosition;
				}
				//byte pushTrans = drawStroke.DrawingAttributes.Transparency;
				//drawStroke.DrawingAttributes.Transparency 
				//	= (byte)(drawStroke.DrawingAttributes.Transparency*alpha);
				inkCollector.Renderer.Draw(g,drawStroke);
				//drawStroke.DrawingAttributes.Transparency = pushTrans;
				highlightDraw(g);
			}
		}

		public override float Alpha
		{
			get
			{
				return (float)((255-stroke.DrawingAttributes.Transparency) / 255f);
			}
			set
			{
				stroke.DrawingAttributes.Transparency = (byte)((1f-value)*255f);
				//this.Invalidate();
			}
		}

		public override bool IsPointingEditButton(int x,int y,bool coerceWheneverFindable)
		{
			return false;
		}

		public override void createCopy(out FigureElement fe)
		{
			//Stroke copiedStroke = ink.CreateStroke(pt);
			Stroke copiedStroke = inkCollector.Ink.CreateStroke(stroke.GetPoints());
			copiedStroke.DrawingAttributes = stroke.DrawingAttributes;
			fe = (FigureElement)(new StrokeElement(this.parentControl,this.priority,this.boundingBox,copiedStroke));
		}
		public override void createCreateEvent(FigureElementList elementList,out CreateObjectEvent coe)
		{// 作っていない
			coe = (CreateObjectEvent)(new CreateStrokeEvent(elementList,this));
		}

		public override bool IsInside(int x, int y,bool coerceWheneverFindable)
		{
			if (!findable && !coerceWheneverFindable) return false;
			Point p = new Point(x,y);
			//inkCollector.Renderer.PixelToInkSpace(this.parentControl.Handle,ref p);
			Graphics g = parentControl.CreateGraphics();
			inkCollector.Renderer.PixelToInkSpace(g,ref p);
			g.Dispose();

			return stroke.HitTest(p,stroke.DrawingAttributes.Width/2);
		}


		protected float playPosition = 1.0f;
		public float PlayPosition
		{
			get{return playPosition;}
			set{playPosition = value;}
		}

	}

	// *****************************
	public class RecogGroupElement : ElementGroupElement
	{
		protected internal FigureElementList recogGroupElementList;
		public RecogGroupElement(Control parentCont,int prio,Rectangle r,FigureElementList list,FigureElementList rlist) : base(parentCont,prio,r,list)
		{
			recogGroupElementList = rlist;
		}
		public override void createCopy(out FigureElement fe)
		{
			FigureElementList newList = new FigureElementList();
			newList.Add(this.groupElementList);
			FigureElementList newrList = new FigureElementList();
			newrList.Add(this.recogGroupElementList);
			fe = (FigureElement)(new RecogGroupElement(this.parentControl,this.priority,this.boundingBox,newList,newrList));
		}
		public override void createCreateEvent(FigureElementList elementList, out CreateObjectEvent coe)
		{
			coe = (CreateObjectEvent)(new CreateRecogGroupEvent(elementList,this));
			//coe = (CreateObjectEvent)(new CreateElementGroupEvent(elementList,this));
		}
		public override void moveRerative(int addx,int addy) 
		{
			recogGroupElementList.moveRerative(addx,addy);
			base.moveRerative(addx,addy);			
		}
		public override void Resize(int x,int y,int w,int h)
		{
			recogGroupElementList.Resize(boundingBox,x,y,w,h);
			base.Resize(x,y,w,h);
		}
		public override void draw(Graphics g)
		{
			if(visible)
			{
				//groupElementList.draw(g,false);
				highlightDraw(g);
			}
		}

	}
/*
	[TestFixture]
	public class RecogGroupElementTest
	{
		[Test]
		public void CreateTest()
		{
			RecogGroupElement rge = new RecogGroupElement(-1,new Rectangle(),new FigureElementList(),new CreateRectangleEvent(new FigureElementList(),-1,new Rectangle(),Color.Black,Color.Black,1));
			Assertion.AssertNotNull(rge);
		}
	}
	*/
}